using System;
using ICommonLibrary.Service;

namespace ICommonLibrary.Cache {

    public abstract class AbstractCache : ServiceBase, ICache {

        protected abstract CacheItem<T> GetItem<T>(string key);
        
        public abstract void Remove(string key);
        public abstract void Put(string key, object value);
        public abstract void Put(string key, object value, TimeSpan expiration);
        public abstract int Size { get; }
        public abstract void Clear();

        public T Get<T>(string key) {
            var item = GetItem<T>(key);
            if (!item.Found) {
                return default(T);
            }
            return item.Value;
        }

        public T Get<T>(string key, Func<T> itemCreator, bool cacheNewItem) {
            var item = GetItem<T>(key);
            if (!item.Found) {
                var value = itemCreator();
                if (value != null && cacheNewItem) {
                    Put(key, value);
                }
                return value;
            }
            return item.Value;
        }

        public T Get<T>(string key, Func<T> itemCreator, TimeSpan expiration, bool cacheNewItem) {
            var item = GetItem<T>(key);
            if (!item.Found) {
                var value = itemCreator();
                if (value != null && cacheNewItem) {
                    Put(key, value, expiration);
                }
                return value;
            }
            return item.Value;
        }

    }

    public class CacheItem<T> {

        public bool Found { get; set; }
        public T Value { get; set; }

        public CacheItem(bool found, T value) {
            Found = found;
            Value = value;
        }
    }
}